package com.hongfan.gateway.config;

import cn.hutool.core.util.ArrayUtil;
import com.hongfan.gateway.authorization.JwtAccessManager;
import com.hongfan.gateway.exception.RequestAccessDeniedHandler;
import com.hongfan.gateway.exception.RequestAuthenticationEntryPoint;
import com.hongfan.gateway.filter.CorsFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;

import javax.annotation.Resource;

/**
 * 网关的Oauth2.0资源的配置类
 *
 * @author zcs
 * @since 2023/10/17
 */
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    /**
     * jwt鉴权管理
     */
    @Resource
    JwtAccessManager accessManager;
    /**
     * token过期的异常处理
     */
    @Resource
    RequestAuthenticationEntryPoint requestAuthenticationEntryPoint;
    /**
     * 权限不足异常处理
     */
    @Resource
    RequestAccessDeniedHandler requestAccessDeniedHandler;

    /**
     * 白名单
     */
    @Resource
    IgnoreUrlsConfig ignoreUrlsConfig;
    /**
     * token效验管理器
     */
    @Resource
    ReactiveAuthenticationManager tokenAuthenticationManager;
    /**
     * 跨域
     */
    @Resource
    private CorsFilter corsFilter;

    @Bean
    SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
        //认证过滤器，放入认证管理器tokenAuthenticationManager。利用认证管理器进行令牌效验
        AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(tokenAuthenticationManager);
        authenticationWebFilter.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter());

        http.httpBasic().disable().
                csrf().disable().
                authorizeExchange().pathMatchers(ArrayUtil.toArray(ignoreUrlsConfig.getUrls(), String.class)).permitAll()
                //其他人的请求必须鉴权，使用鉴权管理器
                .anyExchange().access(accessManager)
                //鉴权的异常处理,权限不足，token失效
                .and().exceptionHandling()
                .authenticationEntryPoint(requestAuthenticationEntryPoint)
                .accessDeniedHandler(requestAccessDeniedHandler)
                .and()
                //跨域过滤器
                .addFilterAfter(corsFilter, SecurityWebFiltersOrder.CORS)
                .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION);
        return http.build();
    }
}
